/**
 * Copyright &copy; 2021-2026
 */
package org.dylan.common.base.tree;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.dylan.common.base.entity.TreeEntity;
import org.dylan.common.base.dto.TreeDTO;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;

/**
 * 树形结构 Service 基类
 *
 * @author Dylan
 * @since 2024-10-24
 */
@Slf4j
@Transactional(rollbackFor = Throwable.class)
public abstract class TreeService<D extends TreeMapper<T>, T extends TreeEntity<T>> extends ServiceImpl<D, T> {

    @Override
    public boolean saveOrUpdate(T entity) {
        T parent;
        // 如果没有设置父节点，则代表为跟节点，有则获取父节点实体
        if (TreeDTO.getRootId().equals(entity.getParentId()) || StrUtil.isBlank(entity.getParentId())) {
            parent = null;
        } else {
            parent = super.getById(entity.getParentId());
        }
        if (parent == null) {
            try {
                parent = getEntityClass().getConstructor().newInstance();
                parent.setId(TreeDTO.getRootId());

            } catch (Exception e) {
                log.error("父节点解析异常", e);
            }
            entity.setParentId(parent.getId());
            parent.setParentIds(StrUtil.EMPTY);
        }
        // 获取修改前的parentIds，用于更新子节点的parentIds
        String oldParentIds = StrUtil.isNotBlank(entity.getId()) ? super.getById(entity.getId()).getParentIds() : null;

        // 设置新的父节点串
        entity.setParentIds(parent.getParentIds() + parent.getId() + ",");
        // 保存或更新实体
        super.saveOrUpdate(entity);
        LambdaQueryWrapper<T> queryWrapper = new LambdaQueryWrapper<>((Class<T>) entity.getClass()).like(T::getParentIds, "%," + entity.getId() + ",%");
        List<T> list = super.list(queryWrapper);
        for (T e : list) {
            if (e.getParentIds() != null && oldParentIds != null) {
                e.setParentIds(e.getParentIds().replace(oldParentIds, entity.getParentIds()));
                super.updateById(e);
            }
        }
        return true;
    }

    public List<T> getChildren(T parent) {
        LambdaQueryWrapper<T> queryWrapper = new LambdaQueryWrapper<>((Class<T>) parent.getClass()).eq(T::getParentId, parent.getId());
        return super.list(queryWrapper);
    }

    /**
     * 删除数据
     *
     * @param id 数据唯一标识
     */
    public boolean removeWithChildrenById(String id) {
        LambdaQueryWrapper<T> queryWrapper = new LambdaQueryWrapper<>((Class<T>) getEntityClass()).like(StrUtil.isNotBlank(id), T::getParentIds, "," + id + ",").or().eq(StrUtil.isNotBlank(id), T::getId, id);
        return super.remove(queryWrapper);
    }

    /**
     * 批量删除数据
     */
    public void removeWithChildrenByIds(List<String> idList) {
        idList.stream().forEach(this::removeWithChildrenById);
    }

    /**
     * 获取JSON树形数据。
     *
     * @return {@link T}
     */
    public List<T> treeData() {
        return treeData(null);
    }


    /**
     * 获取JSON树形数据。
     *
     * @param extId 排除的ID
     * @return {@link T}
     */
    public List<T> treeData(String extId) {
        List<T> allList = super.list(new LambdaQueryWrapper<>(getEntityClass()).orderByAsc(T::getSort));
        try {
            T root = getEntityClass().getConstructor().newInstance();
            root.setId(TreeDTO.getRootId());
            List<T> rootTree = this.formatListToTree(root, allList, extId);
            return rootTree;
        } catch (Exception e) {
            log.error("构建树形结构异常", e);
            return null;
        }
    }


    /**
     * 以root为根节点, 将allList从线性列表转为树形列表
     *
     * @param root    根节点, 为空抛出空指针异常
     * @param allList 所有需要参与构造为树的列表
     * @param extId   需要排除在树之外的节点(子节点一并被排除)
     * @return {@link T}
     **/
    public List<T> formatListToTree(T root, List<T> allList, String extId) {
        String rootId = root.getId();

        // 最终的树形态
        List<T> trees = Lists.newArrayList();

        // 把需要构造树的所有列表, 根据以父id作为key, 整理为列表
        Map<String, List<T>> treeMap = Maps.newHashMap();
        for (T entity : allList) {
            List<T> entities = treeMap.get(entity.getParentId());
            if (entities == null) {
                entities = Lists.newLinkedList();
            }

            // 剔除排除项, 构造treeMap, 转递归为线性操作
            if (StrUtil.isBlank(extId) || (!extId.equals(entity.getId()) && entity.getParentIds().indexOf("," + extId + ",") == -1)) {
                entities.add(entity);
                treeMap.put(entity.getParentId(), entities);
            }
        }

        // 没有给定的子树, 返回空树
        if (treeMap.get(rootId) == null || treeMap.get(rootId).isEmpty()) {
            return trees;
        }

        // 开始递归格式化
        List<T> children = treeMap.get(rootId);
        for (T parent : children) {
            formatFillChildren(parent, treeMap);
            trees.add(parent);
        }
        if (StrUtil.equals(rootId, TreeDTO.getRootId())) {
            return children;
        } else {
            root.setChildren(trees);
            return Lists.newArrayList(root);
        }
    }

    /**
     * 从treeMap中取出子节点填入parent, 并递归此操作
     *
     * @param parent  父节点
     * @param treeMap 数据结构转化为的Map结构
     **/
    private void formatFillChildren(T parent, Map<String, List<T>> treeMap) {
        List<T> children = treeMap.get(parent.getId());
        parent.setChildren(children);
        if (children != null && !children.isEmpty()) {
            for (T child : children) {
                formatFillChildren(child, treeMap);
            }
        }
    }
}
